package com.kexio.core.security.jwt;

import com.kexio.core.security.context.UserContext;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * JWT令牌验证器
 *
 * @author Kexio Team
 * @since 1.0.0
 */
public class JwtTokenValidator {

    private static final Logger log = LoggerFactory.getLogger(JwtTokenValidator.class);

    private final JwtService jwtService;

    public JwtTokenValidator(JwtService jwtService) {
        this.jwtService = jwtService;
    }

    /**
     * 验证访问令牌
     *
     * @param accessToken 访问令牌
     * @return 是否有效
     */
    public boolean validateAccessToken(String accessToken) {
        if (accessToken == null || accessToken.trim().isEmpty()) {
            return false;
        }

        try {
            // 验证令牌格式和签名
            if (!jwtService.validateToken(accessToken)) {
                return false;
            }

            // 检查是否为访问令牌
            if (jwtService.isRefreshToken(accessToken)) {
                log.warn("尝试使用刷新令牌作为访问令牌");
                return false;
            }

            // 检查是否过期
            if (jwtService.isTokenExpired(accessToken)) {
                log.debug("访问令牌已过期");
                return false;
            }

            return true;
        } catch (Exception e) {
            log.warn("验证访问令牌时出现异常: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 验证刷新令牌
     *
     * @param refreshToken 刷新令牌
     * @return 是否有效
     */
    public boolean validateRefreshToken(String refreshToken) {
        if (refreshToken == null || refreshToken.trim().isEmpty()) {
            return false;
        }

        try {
            // 验证令牌格式和签名
            if (!jwtService.validateToken(refreshToken)) {
                return false;
            }

            // 检查是否为刷新令牌
            if (!jwtService.isRefreshToken(refreshToken)) {
                log.warn("尝试使用访问令牌作为刷新令牌");
                return false;
            }

            // 检查是否过期
            if (jwtService.isTokenExpired(refreshToken)) {
                log.debug("刷新令牌已过期");
                return false;
            }

            return true;
        } catch (Exception e) {
            log.warn("验证刷新令牌时出现异常: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 从访问令牌中提取用户上下文
     *
     * @param accessToken 访问令牌
     * @return 用户上下文
     */
    public UserContext extractUserContext(String accessToken) {
        if (!validateAccessToken(accessToken)) {
            throw new IllegalArgumentException("无效的访问令牌");
        }

        try {
            Long userId = jwtService.getClaim(accessToken, "userId", Long.class);
            String username = jwtService.getClaim(accessToken, "username", String.class);
            String nickname = jwtService.getClaim(accessToken, "nickname", String.class);
            Long tenantId = jwtService.getClaim(accessToken, "tenantId", Long.class);
            
            @SuppressWarnings("unchecked")
            List<String> roles = jwtService.getClaim(accessToken, "roles", List.class);
            
            @SuppressWarnings("unchecked")
            List<String> permissions = jwtService.getClaim(accessToken, "permissions", List.class);

            return UserContext.builder()
                    .userId(userId)
                    .username(username)
                    .nickname(nickname)
                    .tenantId(tenantId)
                    .roles(roles)
                    .permissions(permissions)
                    .build();
        } catch (Exception e) {
            log.error("提取用户上下文时出现异常: {}", e.getMessage());
            throw new IllegalArgumentException("解析用户信息失败", e);
        }
    }

    /**
     * 获取令牌剩余有效时间
     *
     * @param token 令牌
     * @return 剩余秒数
     */
    public long getRemainingTime(String token) {
        return jwtService.getRemainingSeconds(token);
    }

    /**
     * 检查令牌是否即将过期(默认5分钟内)
     *
     * @param token 令牌
     * @return 是否即将过期
     */
    public boolean isTokenExpiringSoon(String token) {
        return isTokenExpiringSoon(token, 300); // 5分钟
    }

    /**
     * 检查令牌是否即将过期
     *
     * @param token   令牌
     * @param seconds 提前多少秒算即将过期
     * @return 是否即将过期
     */
    public boolean isTokenExpiringSoon(String token, long seconds) {
        long remaining = getRemainingTime(token);
        return remaining > 0 && remaining <= seconds;
    }

    /**
     * 验证令牌并返回用户上下文
     *
     * @param accessToken 访问令牌
     * @return 用户上下文，如果令牌无效则返回null
     */
    public UserContext validateAndExtract(String accessToken) {
        try {
            return validateAccessToken(accessToken) ? extractUserContext(accessToken) : null;
        } catch (Exception e) {
            log.warn("验证并提取用户上下文失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从令牌中获取用户ID
     *
     * @param accessToken 访问令牌
     * @return 用户ID
     */
    public Long getUserId(String accessToken) {
        if (!validateAccessToken(accessToken)) {
            return null;
        }
        return jwtService.getClaim(accessToken, "userId", Long.class);
    }

    /**
     * 从令牌中获取用户名
     *
     * @param accessToken 访问令牌
     * @return 用户名
     */
    public String getUsername(String accessToken) {
        if (!validateAccessToken(accessToken)) {
            return null;
        }
        return jwtService.getClaim(accessToken, "username", String.class);
    }

    /**
     * 从令牌中获取租户ID
     *
     * @param accessToken 访问令牌
     * @return 租户ID
     */
    public Long getTenantId(String accessToken) {
        if (!validateAccessToken(accessToken)) {
            return null;
        }
        return jwtService.getClaim(accessToken, "tenantId", Long.class);
    }
}
